package com.example.springboottest.example.rabbitmq.p2p;

import com.example.springboottest.base.AbstractService;
import com.example.springboottest.example.rabbitmq.RabbitUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * 正常的发送流程
 * 1、生产者连接到 RabbitMQ Broker 建立一个连接( Connection) ，开启 个信道 (Channel)
 * 2、生产者声明一个交换器 ，并设置相关属性，比如交换机类型、是否持久化等
 * 3、生产者声明一个队列井设置相关属性，比如是否排他、是否持久化、是否自动删除等
 * 4、生产者通过路由键将交换器和队列绑定起来
 * 5、生产者发送消息至 RabbitMQ Broker ，其中包含路由键、交换器等信息
 * 6、相应的交换器根据接收到的路由键查找相匹配的队列
 * 7、如果找到 ，则将从生产者发送过来的消息存入相应的队列中
 * 8、如果没有找到 ，则根据生产者配置的属性选择丢弃还是回退给生产者
 * 9、关闭信道
 * 10、关闭连接
 */
public class RabbitMQSend extends AbstractService {
    public static String CLIENT_ID = "faw_fbom";
    public static String EXCHANGE_IDM = "idm_exchange";
    public static String QUEUE_NAME = "orgUserSync";
    public static String QUEUE_A = QUEUE_NAME + CLIENT_ID;
    public static String BASIC_ROUTING_KEY = "topic.idm.basic." + CLIENT_ID;
    public static String CONSUMER_TAG = "rabbit_faw_fbom";

    public static void main(String[] args) {
        new RabbitMQSend().send();
    }

    /**
     * exchange有四种类型fanout、topic、direct和headers
     * fanout： 它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。
     * direct： 它会把消息路由到那些 BindingKey RoutingKey完全匹配的队列中。
     * topic：  对direct进行了扩展，支持通配符。
     * headers：不依赖于路由键的匹配规则来路由消息，而是根据发送的消息内容中headers属性进行匹配。性能会很差，而且也不实用，基本上不会看到它的存在。
     */
    public void send() {
        ConnectionFactory factory = RabbitUtil.getConnectionFactory();
        Connection connection = null;
        Channel channel = null;
        Boolean autoAck = true;//自动确认消费，只要消费者从队列中获取到消息，服务器都认为消息已经成功被消费
        try {
            connection = factory.newConnection();//创建连接
            channel = connection.createChannel();//创建消息通道
            // 创建一个 type="direct" 、持久化的、非自动删除的交换器
            channel.exchangeDeclare(EXCHANGE_IDM, "direct", true, false, null);
            //创建一个持久化、非排他的、非自动删除的队列
            channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//            将交换器与队列通过路由键绑定
//            channel.queueBind(QUEUE_NAME, EXCHANGE_IDM, BASIC_ROUTING_KEY);
            //发送一条持久化的消息: hello world !
            String message = "Hello World ! 你好 世界";
            /**
             * mandatory 参数告诉服务器至少将该消息路由到一个队列中，否则将消息返回给生产者。
             * mandatory 设置true,表明会返回消息给发送者，反之，直接丢弃，默认fasle
             * immediate 参数告诉服务器 如果该消息关联的队列上有消费者， 立刻投递:
             * 如果所有匹配的队列上都没有消费者，则直接将消息返还给生产者 不用将消息存入队列而等待消费者了
             * RabbitMQ 3.0 版本开始去掉了对 imrnediate 参数的支持
             */
            try {
                channel.txSelect();
                channel.basicPublish(EXCHANGE_IDM, BASIC_ROUTING_KEY, true,
                        MessageProperties.PERSISTENT_TEXT_PLAIN,
                        message.getBytes());
                int i = 9 / 0;
                channel.txCommit();
            } catch (Exception e) {
                e.printStackTrace();
                channel.txRollback();
            }
            /**
             * 当没有成功发送到queue的时候，才会返回结果
             */
            channel.addReturnListener(new ReturnListener() {
                public void handleReturn(int replyCode, String replyText,
                                         String exchange, String routingKey,
                                         AMQP.BasicProperties basicProperties, byte[] body) throws IOException {
                    String message = new String(body);
                    System.out.println("Basic.Return 返回的结果是: " + message);
                }
            });
        } catch (
                Exception e) {
            e.printStackTrace();
            logger.error("rabbitMQ消费者监控服务启动失败，创建队列连接失败：" + e.getMessage());
        } finally {
            //关闭资源
            try {
                channel.close();
                connection.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}